package com.atguigu.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: shenhao
 * @CreatTime: 2024/9/27 17:55
 * @Version: 1.0
 */
public class SaleTicketDemo {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        // 创建三个线程;
        Thread thread1 = new Thread(()->{for (int i = 0; i < 100; i++) ticket.saleTicket();},"售票员A");
        Thread thread2 = new Thread(()->{for (int i = 0; i < 100; i++) ticket.saleTicket();},"售票员B");
        Thread thread3 = new Thread(()->{for (int i = 0; i < 100; i++) ticket.saleTicket();},"售票员C");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//创建一个资源类,高内聚,低耦合,那么卖票,票数属性和卖票方法需要在一个资源类里
class Ticket{
    private int diverTicket=100;//初始化为100张票
    // 版本一
    /*public synchronized void saleTicket(){
        if(diverTicket>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(diverTicket--)+"张票\t还剩下了"+diverTicket+"张票");
        }
        try {
            TimeUnit.MICROSECONDS.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }*/
    //版本二, synchronized代码块
    /*public void saleTicket(){
        synchronized (this){
            if(diverTicket>0){
                System.out.println(Thread.currentThread().getName()+"卖出了第"+(diverTicket--)+"张票\t还剩下了"+diverTicket+"张票");

            }
        }
        try {
            TimeUnit.MICROSECONDS.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }*/
// 代码三,使用 java.util.concurrent.locks的工具锁
    ////V3  JUC start
    Lock lock = new ReentrantLock();// 需要写到方法外,当作一个属性,那么就是唯一的
    public void saleTicket(){
        lock.lock();
        try {
            if(diverTicket>0){
                System.out.println(Thread.currentThread().getName()+"卖出了第"+(diverTicket--)+"张票\t还剩下了"+diverTicket+"张票");
            }
        }finally {
            lock.unlock();
        }
        try {// 睡眠事件,要写到锁外边
            TimeUnit.MICROSECONDS.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}